#ifndef CodeTextView_First
#define CodeTextView_First
#ifdef __GNUG__
#pragma interface
#endif

#include "VObjectTView.h"
#include "TextFormatter.h"

class CharStyle;
class CodeReformatter;
class PrettyPrinter;
class StyledText;
class RunArray;

//---- CodeTextView ------------------------------------------------------------
// a TextView for editing programm text
// adds: auto indenting
//       pretty printing
//       highlighting matching brackets
//       (double clicking on a bracket selects the text enclosed by the brackets)

class CodeTextView: public VObjectTextView {
public:
	MetaDef(CodeTextView);

	CodeTextView(EvtHandler *eh, const Rectangle &r, VObjectText *t, bool wrap= TRUE,
		TextViewFlags= eTextViewDefault, const Point &border= gBorder,
		TViewAlign m= eTViewLeft, int id= cIdNone);
	~CodeTextView();

	//---- formatting of source code
	virtual PrettyPrinter *MakePrettyPrinter(Text *t, CharStyle *cs, CharStyle *fs,
			CharStyle *cds, CharStyle *ps);
	void FormatCode();
	bool NeedsReformat();
	void Reformat();
	void InvalidateFormatting();
	void SetDefaultStyle();
	void SetFont(Font *fp);

	//---- controller methods
	Command *DoLeftButtonDownCommand(Point, Token, int); // matching brackets
	Command *DoKeyCommand(int, Token);      // auto indent
	Command *DoMenuCommand(int);
	Command *DoOtherEventCommand(Point p, Token t);
	Command *DoCursorKeyCommand(EvtCursorDir, Token);
	void DoObserve(int id, int part, void *what, Object *op);
	void SetAutoIndent(bool);
	bool GetAutoIndent();
	Command *PasteData(Data *data);

protected:
	void MatchBracketForward(int from, int obracket, int cbracket);
	void MatchBracketBackward(int from, int obracket, int cbracket);
	void ExitCursorMode();
	int CursorPos(int ch, int line, EvtCursorDir d, Point);
	void SetupStyles(Font *fp);

protected:
	bool autoIndent, needsReformat;
	Point cursorPos;
	CodeReformatter *reformatter;
	CharStyle *commentStyle, *functionStyle, *classDeclStyle, *plainStyle;
};

inline bool CodeTextView::NeedsReformat()
	{ return needsReformat; }
inline void CodeTextView::SetAutoIndent(bool b)
	{ autoIndent= b; }
inline bool CodeTextView::GetAutoIndent()
	{ return autoIndent; }
inline void CodeTextView::ExitCursorMode()
	{ cursorPos= gPoint_1; }

//---- CodeAnalyzer ------------------------------------------------------------

class CodeAnalyzer {
public:
	CodeAnalyzer(Text *t);
	void Doit();

protected:
	virtual void Start();
	virtual void Comment(int line, int start, int end);
	virtual void ClassDecl(int line, int start, int end, const char *name);
	virtual void Function(int line, int start, int end, const char *name,
						const char *classname);
	virtual void End();

private:
	void FoundComment(AutoTextIter *next);
	void FoundEndOfLineComment(AutoTextIter *next);
	void FoundFunctionOrMethod(int at, int lastComment);
	void FoundClassDecl(int at);
	bool IsClassDecl(int at);

protected:
	Text *text;

private:
	bool inDefine;
	int lastComment, prevCh, c;
	int braceStack, inString, isescape;
	int inClass, line;
	int canBeClas, canBeFunction;
};

//---- PrettyPrinter ----------------------------------------------------------

class PrettyPrinter: public CodeAnalyzer {
public:
	PrettyPrinter(Text *t, CharStyle *cs, CharStyle *fs, CharStyle *cds,
								CharStyle *ps);
protected:
	void Start();
	void Comment(int line, int start, int end);
	void ClassDecl(int line, int start, int end, const char *name);
	void Function(int line, int start, int end, const char *name, const char *classname);
	void End();
private:
	StyledText *stext;
	RunArray *st;
	CharStyle *commentStyle, *functionStyle, *classDeclStyle, *plainStyle;
};

#endif
